#include "stdafx.h"
#include "log_thread.h"
#include <process.h>
#include "tools.h"
#include "simple_log_impl.h"

unsigned int __stdcall LogThreadFunc(void* args);
std::shared_ptr<LogThread> LogThread::log_thread_;

LogThread::LogThread()
    : thread_(NULL),
      slog_ref_(0) {
}

LogThread::~LogThread() {
}

LogThread* LogThread::Get() {
    if (log_thread_ == NULL)
        log_thread_.reset(new LogThread());

    return log_thread_.get();
}

void LogThread::Start() {
     AutoLock lock(slog_ref_lock_);
     ++slog_ref_;

     if (thread_ == NULL) {
         thread_ = (HANDLE)_beginthreadex(NULL, 0, LogThreadFunc, this, 0, &thread_id_);
     }
}

void LogThread::Stop() {
    AutoLock lock(slog_ref_lock_);
    --slog_ref_;

    if (slog_ref_ == 0) {
        ::PostThreadMessage(thread_id_, WM_QUIT, 0, 0);

        ::WaitForSingleObject(thread_, INFINITE);
        ::CloseHandle(thread_);
        thread_ = NULL;
    }
}

void LogThread::Run() {
    MSG msg;

    BOOL ret;
    while ((ret = GetMessage(&msg, NULL, 0, 0)) != 0) {
        if (ret == -1) {
            // handle the error and possibly exit
        }
        else {
            HandleMessage(&msg);
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
}

void LogThread::HandleMessage(MSG* msg) {
    switch (msg->message)
    {
    case WM_WRITELOG:
        OnWriteLog(msg->wParam, msg->lParam);
        break;
    default:
        break;
    }
}

void LogThread::PostThreadMessag(UINT msg, WPARAM wparam, LPARAM lparam) {
    ::PostThreadMessage(thread_id_, msg, wparam, lparam);
}

void LogThread::OnWriteLog(WPARAM wparam, LPARAM lparam) {
    SimpleLogImpl* slog = reinterpret_cast<SimpleLogImpl*>(wparam);
    std::wstring* log = reinterpret_cast<std::wstring*>(lparam);

    if (slog && log) {
        slog->WriteLog(*log);
        delete log;
    }
}


static unsigned int __stdcall LogThreadFunc(void* args)
{
    SetThreadName(GetCurrentThreadId(), "simple log thread");

    LogThread* mgr = reinterpret_cast<LogThread*>(args);
    if (mgr != NULL)
        mgr->Run();

    _endthreadex(0);

    return 0;
}